home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 7 / Amiga Format AFCD07 (Dec 1996, Issue 91).iso / serious / shareware / programming / aros / filesys / ramdev.c < prev   
C/C++ Source or Header  |  1996-09-12  |  33KB  |  1,298 lines

  1. /*
  2.     (C) 1995-96 AROS - The Amiga Replacement OS
  3.     $Id: ramdev.c,v 1.2 1996/08/01 17:41:23 digulla Exp $
  4.     $Log: ramdev.c,v $
  5.     Revision 1.2  1996/08/01 17:41:23  digulla
  6.     Added standard header for all files
  7.  
  8.     Desc:
  9.     Lang:
  10. */
  11. #include <exec/errors.h>
  12. #include <exec/types.h>
  13. #include <exec/resident.h>
  14. #include <exec/memory.h>
  15. #include <exec/semaphores.h>
  16. #include <clib/exec_protos.h>
  17. #include <utility/tagitem.h>
  18. #include <clib/utility_protos.h>
  19. #include <dos/dosextens.h>
  20. #include <dos/dosasl.h>
  21. #include <dos/filesystem.h>
  22. #include <clib/dos_protos.h>
  23. #include <aros/libcall.h>
  24. #ifdef __GNUC__
  25.     #include "ramdev_gcc.h"
  26. #endif
  27.  
  28. #define NEWLIST(l)                          \
  29. ((l)->lh_Head=(struct Node *)&(l)->lh_Tail, \
  30.  (l)->lh_Tail=NULL,                         \
  31.  (l)->lh_TailPred=(struct Node *)(l))
  32.  
  33. extern const char name[];
  34. extern const char version[];
  35. extern const APTR inittabl[4];
  36. extern void *const functable[];
  37. extern const UBYTE datatable;
  38. extern struct rambase *ramdev_init();
  39. extern void ramdev_open();
  40. extern BPTR ramdev_close();
  41. extern BPTR ramdev_expunge();
  42. extern int ramdev_null();
  43. extern void ramdev_beginio();
  44. extern LONG ramdev_abortio();
  45. extern void deventry();
  46. extern const char end;
  47.  
  48. /* Device node */
  49. struct cnode
  50. {
  51.     struct MinNode node;
  52.     LONG type;            /* ST_LINKDIR */
  53.     char *name;            /* Link's name */
  54.     struct cnode *self;        /* Pointer to top of structure */
  55.     struct hnode *link;        /* NULL */
  56.     LONG usecount;        /* >0 usecount locked:+(~0ul/2+1) */
  57.     ULONG protect;        /* 0 */
  58.     char *comment;        /* NULL */
  59.     struct vnode *volume;    /* Pointer to volume */
  60.     struct DosList *doslist;    /* Pointer to doslist entry */
  61. };
  62.  
  63. /* Volume node */
  64. struct vnode
  65. {
  66.     struct MinNode node;
  67.     LONG type;            /* ST_USERDIR */
  68.     char *name;            /* Directory name */
  69.     struct vnode *self;        /* Points to top of structure */
  70.     struct hnode *link;        /* This one is linked to me */
  71.     LONG usecount;        /* >0 usecount locked:+(~0ul/2+1) */
  72.     ULONG protect;        /* 0 */
  73.     char *comment;        /* NULL */
  74.     struct MinList list;    /* Contents of directory */
  75.     struct MinList waiting;    /* IORequests waiting on dismountage */
  76.     ULONG volcount;        /* number of handles on this volume */
  77.     struct DosList *doslist;    /* Pointer to doslist entry */
  78. };
  79.  
  80. /* Directory node */
  81. struct dnode
  82. {
  83.     struct MinNode node;
  84.     LONG type;            /* ST_USERDIR */
  85.     char *name;            /* Directory name */
  86.     struct vnode *volume;    /* Volume's root directory */
  87.     struct hnode *link;        /* This one is linked to me */
  88.     LONG usecount;        /* >0 usecount locked:+(~0ul/2+1) */
  89.     ULONG protect;        /* protection bits */
  90.     char *comment;        /* Some comment */
  91.     struct MinList list;    /* Contents of directory */
  92. };
  93.  
  94. /* File node */
  95. struct fnode
  96. {
  97.     struct MinNode node;
  98.     LONG type;            /* ST_FILE */
  99.     char *name;            /* Filename */
  100.     struct vnode *volume;    /* Volume's root directory */
  101.     struct hnode *link;        /* This one is linked to me */
  102.     LONG usecount;        /* >0 usecount locked:+(~0ul/2+1) */
  103.     ULONG protect;        /* protection bits */
  104.     char *comment;        /* Some file comment */
  105.     LONG size;            /* Filesize */
  106.     UBYTE *blocks[16];        /* Upto 0x1000 bytes */
  107.     UBYTE **iblocks[4];        /* Upto 0x41000 bytes */
  108.     UBYTE ***i2block;        /* Upto 0x1041000 bytes */
  109.     UBYTE ****i3block;        /* Upto 0x101041000 bytes */
  110. };
  111.  
  112. /* Softlink node */
  113. struct snode
  114. {
  115.     struct MinNode node;
  116.     LONG type;            /* ST_SOFTLINK */
  117.     char *name;            /* Link's name */
  118.     struct vnode *volume;    /* Volume's root directory */
  119.     struct hnode *link;        /* This one is hardlinked to me */
  120.     LONG usecount;        /* >0 usecount locked:+(~0ul/2+1) */
  121.     ULONG protect;        /* protection bits */
  122.     char *comment;        /* Some file comment */
  123.     char *contents;        /* Contents of soft link */
  124. };
  125.  
  126. /* Hardlink node */
  127. struct hnode
  128. {
  129.     struct MinNode node;
  130.     LONG type;            /* ST_LINKDIR */
  131.     char *name;            /* Link's name */
  132.     struct vnode *volume;    /* Volume's root directory */
  133.     struct hnode *link;        /* This one is hardlinked to me */
  134.     LONG usecount;        /* >0 usecount locked:+(~0ul/2+1) */
  135.     ULONG protect;        /* protection bits */
  136.     char *comment;        /* Some file comment */
  137.     struct hnode *orig;        /* original object */
  138. };
  139.  
  140. #define BLOCKSIZE    256
  141. #define PBLOCKSIZE    (256*sizeof(UBYTE *))
  142.  
  143. struct filehandle
  144. {
  145.     struct dnode *node;
  146.     ULONG position;
  147. };
  148.  
  149. int entry(void)
  150. {
  151.     /* If the device was executed by accident return error code. */
  152.     return -1;
  153. }
  154.  
  155. const struct Resident resident=
  156. {
  157.     RTC_MATCHWORD,
  158.     (struct Resident *)&resident,
  159.     (APTR)&end,
  160.     RTF_AUTOINIT,
  161.     1,
  162.     NT_LIBRARY,
  163.     0,
  164.     (char *)name,
  165.     (char *)&version[6],
  166.     (ULONG *)inittabl
  167. };
  168.  
  169. const char name[]="ram.handler";
  170.  
  171. const char version[]="$VER: ram handler 1.0 (28.3.96)\n\015";
  172.  
  173. const APTR inittabl[4]=
  174. {
  175.     (APTR)sizeof(struct rambase),
  176.     (APTR)functable,
  177.     (APTR)&datatable,
  178.     &ramdev_init
  179. };
  180.  
  181. void *const functable[]=
  182. {
  183.     &ramdev_open,
  184.     &ramdev_close,
  185.     &ramdev_expunge,
  186.     &ramdev_null,
  187.     &ramdev_beginio,
  188.     &ramdev_abortio,
  189.     (void *)-1
  190. };
  191.  
  192. const UBYTE datatable=0;
  193.  
  194. __AROS_LH2(struct rambase *, init,
  195.  __AROS_LA(struct rambase *, rambase, D0),
  196.  __AROS_LA(BPTR,             segList,   A0),
  197.        struct ExecBase *, SysBase, 0, ramdev)
  198. {
  199.     __AROS_FUNC_INIT
  200.     
  201.     /* This function is single-threaded by exec by calling Forbid. */
  202.  
  203.     struct MsgPort *port;
  204.     struct Task *task;
  205.     struct SignalSemaphore *semaphore;
  206.     APTR stack;
  207.     
  208.     /* Store arguments */
  209.     rambase->sysbase=SysBase;
  210.     rambase->seglist=segList;
  211.     rambase->dosbase=(struct DosLibrary *)OpenLibrary("dos.library",39);
  212.     if(rambase->dosbase!=NULL)
  213.     {
  214.         rambase->utilitybase=(struct UtilityBase *)OpenLibrary("utility.library",39);
  215.         if(rambase->utilitybase!=NULL)
  216.         {    
  217.         port=(struct MsgPort *)AllocMem(sizeof(struct MsgPort),MEMF_PUBLIC|MEMF_CLEAR);
  218.         if(port!=NULL)
  219.         {
  220.         rambase->port=port;
  221.         NEWLIST(&port->mp_MsgList);
  222.         port->mp_Node.ln_Type=NT_MSGPORT;
  223.         port->mp_SigBit=SIGF_SINGLE;
  224.  
  225.         task=(struct Task *)AllocMem(sizeof(struct Task),MEMF_PUBLIC|MEMF_CLEAR);
  226.         if(task!=NULL)
  227.         {
  228.             port->mp_SigTask=task;
  229.             port->mp_Flags=PA_IGNORE;
  230.             NEWLIST(&task->tc_MemEntry);
  231.             task->tc_Node.ln_Type=NT_TASK;
  232.             task->tc_Node.ln_Name="ram.handler task";
  233.         
  234.             stack=AllocMem(2048,MEMF_PUBLIC);
  235.             if(stack!=NULL)
  236.             {
  237.             task->tc_SPLower=stack;
  238.             task->tc_SPUpper=(BYTE *)stack+2048;
  239. #if STACK_GROWS_DOWNWARDS
  240.             task->tc_SPReg=(BYTE *)task->tc_SPUpper-SP_OFFSET-sizeof(APTR);
  241.             ((APTR *)task->tc_SPUpper)[-1]=rambase;
  242. #else
  243.             task->tc_SPReg=(BYTE *)task->tc_SPLower-SP_OFFSET+sizeof(APTR);
  244.             *(APTR *)task->tc_SPLower=rambase;
  245. #endif
  246.         
  247.             semaphore=(struct SignalSemaphore *)AllocMem(sizeof(struct SignalSemaphore),MEMF_PUBLIC|MEMF_CLEAR);
  248.             if(semaphore!=NULL)
  249.             {
  250.                 rambase->sigsem=semaphore;
  251.                 InitSemaphore(semaphore);
  252.             
  253.                 if(AddTask(task,deventry,NULL)!=NULL)
  254.                     return rambase;
  255.                 
  256.                 FreeMem(semaphore,sizeof(struct SignalSemaphore));
  257.             }
  258.             FreeMem(stack,2048);
  259.             }
  260.             FreeMem(task,sizeof(struct Task));
  261.         }
  262.         FreeMem(port,sizeof(struct MsgPort));
  263.         }
  264.         CloseLibrary((struct Library *)rambase->utilitybase);
  265.     }
  266.     CloseLibrary((struct Library *)rambase->dosbase);
  267.     }
  268.  
  269.     return NULL;
  270.     __AROS_FUNC_EXIT
  271. }
  272.  
  273. /* Use This from now on */
  274. #ifdef SysBase
  275.     #undef SysBase
  276. #endif
  277. #ifdef DOSBase
  278.     #undef DOSBase
  279. #endif
  280. #ifdef UtilityBase
  281.     #undef UtilityBase
  282. #endif
  283. #define SysBase rambase->sysbase
  284. #define DOSBase rambase->dosbase
  285. #define UtilityBase rambase->utilitybase
  286.  
  287. __AROS_LH3(void, open,
  288.  __AROS_LA(struct IOFileSys *, iofs, A1),
  289.  __AROS_LA(ULONG,              unitnum, D0),
  290.  __AROS_LA(ULONG,              flags, D0),
  291.        struct rambase *, rambase, 1, ramdev)
  292. {
  293.     __AROS_FUNC_INIT
  294.     /*
  295.     This function is single-threaded by exec by calling Forbid.
  296.     If you break the Forbid() another task may enter this function
  297.     at the same time. Take care.
  298.     */
  299.  
  300.     /* Keep compiler happy */
  301.     unitnum=0;
  302.     flags=0;
  303.  
  304.     /* I have one more opener. */
  305.     rambase->device.dd_Library.lib_OpenCnt++;
  306.     rambase->device.dd_Library.lib_Flags&=~LIBF_DELEXP;
  307.  
  308.     /* Set returncode */
  309.     iofs->IOFS.io_Error=0;
  310.  
  311.     /* Mark Message as recently used. */
  312.     iofs->IOFS.io_Message.mn_Node.ln_Type=NT_REPLYMSG;
  313.     __AROS_FUNC_EXIT
  314. }
  315.  
  316. __AROS_LH1(BPTR, close,
  317.  __AROS_LA(struct IOFileSys *, iofs, A1),
  318.        struct rambase *, rambase, 2, ramdev)
  319. {
  320.     __AROS_FUNC_INIT
  321.     /*
  322.     This function is single-threaded by exec by calling Forbid.
  323.     If you break the Forbid() another task may enter this function
  324.     at the same time. Take care.
  325.     */
  326.  
  327.     /* Let any following attemps to use the device crash hard. */
  328.     iofs->IOFS.io_Device=(struct Device *)-1;
  329.  
  330.     /* I have one fewer opener. */
  331.     if(!--rambase->device.dd_Library.lib_OpenCnt)
  332.     {
  333.     /* Delayed expunge pending? */
  334.     if(rambase->device.dd_Library.lib_Flags&LIBF_DELEXP)
  335.         /* Then expunge the device */
  336.         return expunge();
  337.     }
  338.     return 0;
  339.     __AROS_FUNC_EXIT
  340. }
  341.  
  342. __AROS_LH0(BPTR, expunge, struct rambase *, rambase, 3, ramdev)
  343. {
  344.     __AROS_FUNC_INIT
  345.  
  346.     BPTR ret;
  347.     /*
  348.     This function is single-threaded by exec by calling Forbid.
  349.     Never break the Forbid() or strange things might happen.
  350.     */
  351.  
  352.     /* Test for openers. */
  353.     if(rambase->device.dd_Library.lib_OpenCnt)
  354.     {
  355.     /* Set the delayed expunge flag and return. */
  356.     rambase->device.dd_Library.lib_Flags|=LIBF_DELEXP;
  357.     return 0;
  358.     }
  359.  
  360.     /* Kill device task and free all resources */
  361.     RemTask(rambase->port->mp_SigTask);
  362.     FreeMem(rambase->sigsem,sizeof(struct SignalSemaphore));
  363.     FreeMem(((struct Task *)rambase->port->mp_SigTask)->tc_SPLower,2048);
  364.     FreeMem(rambase->port->mp_SigTask,sizeof(struct Task));
  365.     FreeMem(rambase->port,sizeof(struct MsgPort));
  366.     CloseLibrary((struct Library *)rambase->utilitybase);
  367.     CloseLibrary((struct Library *)rambase->dosbase);
  368.  
  369.     /* Get rid of the device. Remove it from the list. */
  370.     Remove(&rambase->device.dd_Library.lib_Node);
  371.  
  372.     /* Get returncode here - FreeMem() will destroy the field. */
  373.     ret=rambase->seglist;
  374.  
  375.     /* Free the memory. */
  376.     FreeMem((char *)rambase-rambase->device.dd_Library.lib_NegSize,
  377.         rambase->device.dd_Library.lib_NegSize+rambase->device.dd_Library.lib_PosSize);
  378.  
  379.     return ret;
  380.     __AROS_FUNC_EXIT
  381. }
  382.  
  383. __AROS_LH0I(int, null, struct rambase *, rambase, 4, ramdev)
  384. {
  385.     __AROS_FUNC_INIT
  386.     return 0;
  387.     __AROS_FUNC_EXIT
  388. }
  389.  
  390. __AROS_LH1(void, beginio,
  391.  __AROS_LA(struct IOFileSys *, iofs, A1),
  392.        struct rambase *, rambase, 5, ramdev)
  393. {
  394.     __AROS_FUNC_INIT
  395.  
  396.     /* WaitIO will look into this */
  397.     iofs->IOFS.io_Message.mn_Node.ln_Type=NT_MESSAGE;
  398.  
  399.     /* Nothing is done quick */
  400.     iofs->IOFS.io_Flags&=~IOF_QUICK;
  401.     
  402.     /* So let the device task do it */
  403.     PutMsg(rambase->port,&iofs->IOFS.io_Message);
  404.     
  405.     __AROS_FUNC_EXIT
  406. }
  407.  
  408. __AROS_LH1(LONG, abortio,
  409.  __AROS_LA(struct IOFileSys *, iofs, A1),
  410.        struct rambase *, rambase, 6, ramdev)
  411. {
  412.     __AROS_FUNC_INIT
  413. #if 0
  414.     if(iofs->IOFS.io_Command==FSA_NOTIFY)
  415.     {
  416.         ObtainSemaphore(rambase->sigsem);
  417.         rambase->iofs=iofs;
  418.         Signal(rambase->port->mp_SigTask,rambase->port->mp_SigBit);
  419.         while(rambase->iofs!=NULL)
  420.             Wait(1<<iofs->IOFS.io_Message.mn_ReplyPort->mp_SigBit);
  421.         ReleaseSemaphore(rambase->sigsem);
  422.     }
  423. #endif
  424.     return 0;
  425.     __AROS_FUNC_EXIT
  426. }
  427.  
  428. static STRPTR Strdup(struct rambase *rambase, STRPTR string)
  429. {
  430.     STRPTR s2=string,s3;
  431.     while(*s2++)
  432.         ;
  433.     s3=(STRPTR)AllocMem(s2-string,MEMF_ANY);
  434.     if(s3!=NULL)
  435.         CopyMem(string,s3,s2-string);
  436.     return s3;
  437. }
  438.  
  439. static void Strfree(struct rambase *rambase, STRPTR string)
  440. {
  441.     STRPTR s2=string;
  442.     if(string==NULL)
  443.         return;
  444.     while(*s2++)
  445.         ;
  446.     FreeMem(string,s2-string);
  447. }
  448.  
  449. static LONG startup(struct rambase *rambase, STRPTR name, struct TagItem *args)
  450. {
  451.     struct filehandle *fhv, *fhc;
  452.     struct DosList *dlv, *dlc;
  453.     struct cnode *dev;
  454.     struct vnode *vol;
  455.  
  456.     /* Get compiler happy */
  457.     args=NULL;
  458.  
  459.     fhv=(struct filehandle*)AllocMem(sizeof(struct filehandle),MEMF_CLEAR);
  460.     if(fhv!=NULL)
  461.     {
  462.     vol=(struct vnode *)AllocMem(sizeof(struct vnode),MEMF_CLEAR);
  463.     if(vol!=NULL)
  464.     {
  465.         vol->name=Strdup(rambase,"Ram Disk");
  466.         if(vol->name!=NULL)
  467.         {
  468.         dlv=MakeDosEntry("Ram Disk",DLT_VOLUME);
  469.         if(dlv!=NULL)
  470.         {
  471.             fhc=(struct filehandle *)AllocMem(sizeof(struct filehandle),MEMF_CLEAR);
  472.             if(fhc!=NULL)
  473.             {
  474.             dev=(struct cnode *)AllocMem(sizeof(struct cnode),MEMF_CLEAR);
  475.             if(dev!=NULL)
  476.             {    
  477.                 dev->name=Strdup(rambase,name);
  478.                 if(dev->name!=NULL)
  479.                 {
  480.                 dlc=MakeDosEntry(name,DLT_DEVICE);
  481.                 if(dlc!=NULL)
  482.                 {
  483.                     vol->type=ST_USERDIR;
  484.                     vol->self=vol;
  485.                     vol->doslist=dlv;
  486.                     NEWLIST((struct List *)&vol->list);
  487.                     fhv->node=(struct dnode *)vol;
  488.                     dlv->dol_Unit  =(struct Unit *)fhv;
  489.                     dlv->dol_Device=&rambase->device;
  490.                     dev->type=ST_LINKDIR;
  491.                     dev->self=dev;
  492.                     dev->volume=vol;
  493.                     dev->doslist=dlc;
  494.                     fhc->node=(struct dnode *)dev;
  495.                     dlc->dol_Unit  =(struct Unit *)fhc;
  496.                     dlc->dol_Device=&rambase->device;
  497.                     if(AddDosEntry(dlv))
  498.                     {
  499.                     if(AddDosEntry(dlc))
  500.                     {
  501.                         rambase->unitcount++;
  502.                         return 0;
  503.                     }
  504.                     RemDosEntry(dlv);
  505.                     }
  506.                     FreeDosEntry(dlc);
  507.                 }
  508.                 Strfree(rambase,dev->name);
  509.                 }
  510.                 FreeMem(dev,sizeof(struct cnode));
  511.             }
  512.             FreeMem(fhc,sizeof(struct filehandle));
  513.             }
  514.             FreeDosEntry(dlv);
  515.         }
  516.         Strfree(rambase,vol->name);
  517.         }
  518.         FreeMem(vol,sizeof(struct vnode));
  519.     }
  520.     FreeMem(fhv,sizeof(struct filehandle));
  521.     }
  522.     return ERROR_NO_FREE_STORE;
  523. }
  524.  
  525. static LONG getblock(struct rambase *rambase, struct fnode *file, LONG block, int mode, UBYTE **result)
  526. {
  527.     ULONG a, i;
  528.     UBYTE **p, **p2;
  529.     
  530.     if(block<0x10)
  531.     {
  532.     p=&file->blocks[block];
  533.     block=0;
  534.     i=0;
  535.     }else if(block<0x410)
  536.     {
  537.     block-=0x10;
  538.     p=(UBYTE **)&file->iblocks[block/0x100];
  539.     block&=0xff;
  540.     i=1;
  541.     }else if(block<0x10410)
  542.     {
  543.     block-=0x410;
  544.     p=(UBYTE **)&file->i2block;
  545.     i=2;
  546.     }else
  547.     {
  548.     block-=0x10410;
  549.     p=(UBYTE **)&file->i3block;
  550.     i=3;
  551.     }
  552.     switch(mode)
  553.     {
  554.     case -1:
  555.         p2=(UBYTE **)*p;
  556.         if(!block)
  557.         *p=NULL;
  558.         p=p2;
  559.         while(i--&&p!=NULL)
  560.         {
  561.             a=(block>>i*8)&0xff;
  562.             p2=(UBYTE **)p[a];
  563.             if(!(block&((1<<i*8)-1)))
  564.             {
  565.             p[a]=NULL;
  566.             if(!a)
  567.                 FreeMem(p,PBLOCKSIZE);
  568.             }
  569.             p=p2;
  570.         }
  571.         if(p!=NULL)
  572.             FreeMem(p,BLOCKSIZE);
  573.         break;
  574.         case 0:
  575.             p=(UBYTE **)*p;
  576.         while(i--&&p!=NULL)
  577.         p=((UBYTE ***)p)[(block>>i*8)&0xff];
  578.         *result=(UBYTE *)p;
  579.         break;
  580.     case 1:
  581.         while(i--)
  582.         {
  583.             if(*p==NULL)
  584.             {
  585.                 *p=AllocMem(PBLOCKSIZE,MEMF_ANY);
  586.                 if(*p==NULL)
  587.                     return ERROR_NO_FREE_STORE;
  588.             }
  589.             p=(UBYTE **)*p+((block>>i*8)&0xff);
  590.         }
  591.         if(*p==NULL)
  592.         {
  593.             *p=AllocMem(BLOCKSIZE,MEMF_CLEAR);
  594.             if(*p==NULL)
  595.                 return ERROR_NO_FREE_STORE;
  596.         }
  597.         *result=*p;
  598.         break;
  599.     }
  600.     return 0;
  601. }
  602.  
  603. static void zerofill(UBYTE *address, ULONG size)
  604. {
  605.     while(size--)
  606.     *address++=0;
  607. }
  608.  
  609. static void shrinkfile(struct rambase *rambase, struct fnode *file, LONG size)
  610. {
  611.     ULONG blocks, block;
  612.     UBYTE *p;
  613.     
  614.     blocks=(size+BLOCKSIZE-1)/BLOCKSIZE;
  615.     block =(file->size+BLOCKSIZE-1)/BLOCKSIZE;
  616.     for(;block-->blocks;)
  617.     (void)getblock(rambase,file,block,-1,&p);
  618.     if(size&0xff)
  619.     {
  620.         (void)getblock(rambase,file,size,0,&p);
  621.         if(p!=NULL)
  622.                zerofill(p+(size&0xff),-size&0xff);
  623.     }
  624.     file->size=size;
  625. }
  626.  
  627. static void delete(struct rambase *rambase, struct fnode *file)
  628. {
  629.     struct hnode *link;
  630.     
  631.     if(file->type!=ST_LINKDIR&&file->link!=NULL)
  632.     {
  633.         link=file->link;
  634.         Strfree(rambase,file->name);
  635.         Strfree(rambase,file->comment);
  636.         file->name=link->name;
  637.         file->link=link->link;
  638.         file->usecount=link->usecount;
  639.         file->protect=link->protect;
  640.         file->comment=link->comment;
  641.     Remove((struct Node *)file);
  642.     Insert(NULL,(struct Node *)file,(struct Node *)link);
  643.     Remove((struct Node *)link);
  644.     FreeMem(link,sizeof(struct hnode));
  645.     return;
  646.     }
  647.     Remove((struct Node *)file);
  648.     Strfree(rambase,file->name);
  649.     Strfree(rambase,file->comment);
  650.     switch(file->type)
  651.     {
  652.         case ST_USERDIR:
  653.             FreeMem(file,sizeof(struct dnode));
  654.             return;
  655.         case ST_FILE:
  656.             shrinkfile(rambase,file,0);
  657.             FreeMem(file,sizeof(struct fnode));
  658.             return;
  659.         case ST_LINKDIR:
  660.             link=((struct hnode *)file)->orig;
  661.             while((struct fnode *)link->link!=file)
  662.                 link=link->link;
  663.             link->link=file->link;
  664.             FreeMem(file,sizeof(struct hnode));
  665.             return;
  666.         case ST_SOFTLINK:
  667.             Strfree(rambase,((struct snode *)file)->contents);
  668.             return;
  669.     }
  670. }
  671.  
  672. static int fstrcmp(char *s1, char *s2)
  673. {
  674.     for(;;)
  675.     {
  676.     if(ToLower(*s1)!=ToLower(*s2))
  677.         return *s1||*s2!='/';
  678.     if(!*s1)
  679.         return 0;
  680.     s1++; s2++;
  681.     }
  682. }
  683.  
  684. static LONG findname(STRPTR *name, struct dnode **dnode)
  685. {
  686.     struct dnode *cur=*dnode;
  687.     char *rest=*name;
  688.  
  689.     for(;;)
  690.     {
  691.     if(cur->type==ST_LINKDIR)
  692.         cur=(struct dnode *)((struct hnode *)cur)->orig;
  693.     if(!*rest)
  694.         break;
  695.     if(*rest=='/')
  696.     {
  697.         if((struct dnode *)cur->volume==cur)
  698.         return ERROR_OBJECT_NOT_FOUND;
  699.         while(cur->node.mln_Pred!=NULL)
  700.         cur=(struct dnode *)cur->node.mln_Pred;
  701.         cur=(struct dnode *)((BYTE *)cur-offsetof(struct dnode,list));
  702.     }else
  703.     {
  704.         if(cur->type==ST_SOFTLINK)
  705.         {
  706.         *dnode=cur;
  707.         *name=rest;
  708.         return ERROR_IS_SOFT_LINK;
  709.         }
  710.         if(cur->type!=ST_USERDIR)
  711.         return ERROR_DIR_NOT_FOUND;
  712.         cur=(struct dnode *)cur->list.mlh_Head;
  713.         for(;;)
  714.         {
  715.         if(cur->node.mln_Succ==NULL)
  716.             return ERROR_OBJECT_NOT_FOUND;
  717.         if(fstrcmp(cur->name,rest))
  718.             break;
  719.         cur=(struct dnode *)cur->node.mln_Succ;
  720.         }
  721.     }
  722.     while(*rest)
  723.         if(*rest++=='/')
  724.             break;
  725.     }
  726.     *dnode=cur;
  727.     return 0;
  728. }
  729.  
  730. static LONG set_file_size(struct rambase *rambase, struct filehandle *handle, LONG *offset, LONG mode)
  731. {
  732.     struct fnode *file=(struct fnode *)handle->node;
  733.     LONG size=*offset;
  734.     
  735.     if(file->type!=ST_FILE)
  736.     return ERROR_OBJECT_WRONG_TYPE;
  737.     switch(mode)
  738.     {
  739.     case OFFSET_BEGINNING:    break;
  740.     case OFFSET_CURRENT:    size+=handle->position; break;
  741.     case OFFSET_END:    size+=file->size; break;
  742.     default:        return ERROR_NOT_IMPLEMENTED;
  743.     }
  744.     if(size<0)
  745.     return ERROR_SEEK_ERROR;
  746.     if(size<file->size)
  747.     shrinkfile(rambase,file,size);
  748.     file->size=*offset=size;
  749.     return 0;
  750. }
  751.  
  752. static LONG read(struct rambase *rambase, struct filehandle *handle, APTR buffer, LONG *numbytes)
  753. {
  754.     struct fnode *file=(struct fnode *)handle->node;
  755.     ULONG num =*numbytes;
  756.     ULONG size=file->size;
  757.     ULONG block, offset;
  758.     UBYTE *buf=buffer, *p;
  759.  
  760.     if(handle->position>=size)
  761.     num=0;
  762.     else if(handle->position+num>size)
  763.     num=size-handle->position;
  764.     block =handle->position/BLOCKSIZE;
  765.     offset=handle->position&(BLOCKSIZE-1);
  766.     size  =BLOCKSIZE-offset;
  767.     while(num)
  768.     {
  769.     if(size>num)
  770.         size=num;
  771.     (void)getblock(rambase,file,block,0,&p);
  772.     if(p!=NULL)
  773.         CopyMem(p+offset,buffer,size);
  774.     else
  775.         zerofill(buffer,size);
  776.     buffer+=size;
  777.     num   -=size;
  778.     block++;
  779.     offset=0;
  780.     size=BLOCKSIZE;
  781.     }
  782.     *numbytes=(UBYTE *)buffer-buf;
  783.     handle->position+=*numbytes;
  784.     return 0;
  785. }
  786.  
  787. static LONG write(struct rambase *rambase, struct filehandle *handle, UBYTE *buffer, LONG *numbytes)
  788. {
  789.     struct fnode *file=(struct fnode *)handle->node;
  790.     ULONG num =*numbytes;
  791.     ULONG size=file->size;
  792.     ULONG block, offset;
  793.     UBYTE *buf=buffer, *p;
  794.     LONG error=0;
  795.  
  796.     if(handle->position+num<0)
  797.     return ERROR_OBJECT_TOO_LARGE;
  798.     block =handle->position/BLOCKSIZE;
  799.     offset=handle->position&(BLOCKSIZE-1);
  800.     size  =BLOCKSIZE-offset;
  801.     while(num)
  802.     {
  803.     if(size>num)
  804.         size=num;
  805.     error=getblock(rambase,file,block,1,&p);
  806.     if(error)
  807.         break;
  808.     CopyMem(buffer,p+offset,size);
  809.     buffer+=size;
  810.     num   -=size;
  811.     block++;
  812.     offset=0;
  813.     size=BLOCKSIZE;
  814.     }
  815.     *numbytes=(UBYTE *)buffer-buf;
  816.     handle->position+=*numbytes;
  817.     if(*numbytes)
  818.     return 0;
  819.     return error;
  820. }
  821.  
  822. static LONG locate_object(struct rambase *rambase, struct filehandle **handle, STRPTR name, ULONG mode)
  823. {
  824.     struct dnode *dir=(*handle)->node;
  825.     struct filehandle *fh;
  826.     LONG error;
  827.  
  828.     error=findname(&name,&dir);
  829.     if((mode&LMF_CREATE)&&error==ERROR_OBJECT_NOT_FOUND)
  830.     {
  831.         char *s=name;
  832.         struct fnode *file;
  833.     while(*s)
  834.         if(*s=='/')
  835.         return error;
  836.         fh=AllocMem(sizeof(struct filehandle),MEMF_CLEAR);
  837.         if(fh!=NULL)
  838.         {
  839.             file=(struct fnode *)AllocMem(sizeof(struct fnode),MEMF_CLEAR);
  840.             if(file!=NULL)
  841.             {
  842.                 file->name=Strdup(rambase,name);
  843.                 if(file->name!=NULL)
  844.                 {
  845.                     file->type=ST_FILE;
  846.                     file->protect=FIBF_READ|FIBF_WRITE|FIBF_EXECUTE|FIBF_DELETE;
  847.                     file->volume=dir->volume;
  848.                     file->volume->volcount++;
  849.                     if(mode&LMF_LOCK)
  850.                         file->usecount=~0ul/2+1;
  851.                     file->usecount++;
  852.                     AddTail((struct List *)&dir->list,(struct Node *)file);
  853.                     fh->node=(struct dnode *)file;
  854.                     *handle=fh;
  855.                     return 0;
  856.                 }
  857.                 FreeMem(file,sizeof(struct fnode));
  858.             }
  859.             FreeMem(fh,sizeof(struct filehandle));
  860.         }
  861.         return ERROR_NO_FREE_STORE;
  862.     }
  863.     if(error)
  864.         return error;
  865.     if((mode&LMF_EXECUTE)&&!(dir->protect&LMF_EXECUTE))
  866.         return ERROR_NOT_EXECUTABLE;
  867.     if((mode&LMF_WRITE)&&!(dir->protect&LMF_WRITE))
  868.     return ERROR_WRITE_PROTECTED;
  869.     if((mode&LMF_READ)&&!(dir->protect&LMF_READ))
  870.     return ERROR_READ_PROTECTED;
  871.     if((mode&LMF_FILE)&&dir->type!=ST_FILE)
  872.     return ERROR_OBJECT_WRONG_TYPE;
  873.     if(mode&LMF_LOCK)
  874.     {
  875.     if(dir->usecount)
  876.         return ERROR_OBJECT_IN_USE;
  877.     dir->usecount=~0ul/2+1;
  878.     }else
  879.         if(dir->usecount<0)
  880.             return ERROR_OBJECT_IN_USE;
  881.     dir->usecount++;
  882.     fh=(struct filehandle *)AllocMem(sizeof(struct filehandle),MEMF_CLEAR);
  883.     if(fh==NULL)
  884.     {
  885.         dir->usecount=(dir->usecount-1)&~0ul/2;
  886.         return ERROR_NO_FREE_STORE;
  887.     }
  888.     if(mode&LMF_CLEAR)
  889.         shrinkfile(rambase,(struct fnode *)dir,0);
  890.     dir->volume->volcount++;
  891.     fh->node=dir;
  892.     *handle=fh;
  893.     return 0;
  894. }
  895.  
  896. static LONG free_lock(struct rambase *rambase, struct filehandle *filehandle)
  897. {
  898.     struct dnode *dnode=filehandle->node;
  899.     dnode->usecount=(dnode->usecount-1)&~0ul/2;
  900.     FreeMem(filehandle,sizeof(struct filehandle));
  901.     dnode->volume->volcount--;
  902.     return 0;
  903. }
  904.  
  905. static LONG seek(struct rambase *rambase, struct filehandle *filehandle, LONG *posh, LONG *posl, LONG mode)
  906. {
  907.     struct fnode *file=(struct fnode *)filehandle->node;
  908.     LONG pos=*posl;
  909.     
  910.     if((pos<0?-1:0)!=*posh)
  911.         return ERROR_SEEK_ERROR;
  912.     if(file->type!=ST_FILE)
  913.     return ERROR_OBJECT_WRONG_TYPE;
  914.     switch(mode)
  915.     {
  916.         case OFFSET_BEGINNING:    break;
  917.     case OFFSET_CURRENT:    pos+=filehandle->position; break;
  918.     case OFFSET_END:    pos+=file->size; break;
  919.     default:        return ERROR_NOT_IMPLEMENTED;
  920.     }
  921.     if(pos<0)
  922.     return ERROR_SEEK_ERROR;
  923.     *posh=0;
  924.     *posl=filehandle->position;
  925.     filehandle->position=pos;
  926.     return 0;
  927. }
  928. #if 0
  929. static LONG examine_node(struct fnode *file, ULONG **buffer, ULONG *size, ULONG type, ULONG namesize, ULONG commsize)
  930. {
  931.     ULONG *buf=*buffer;
  932.     ULONG siz=*size/sizeof(ULONG),bsize;
  933.     STRPTR s1=NULL, s2;
  934.     int i, k;
  935.     
  936.     for(i=1;type;i++)
  937.     {
  938.     if(type&1)
  939.     {
  940.         if(!siz)
  941.             return ERROR_BUFFER_OVERFLOW;
  942.         switch(i)
  943.         {
  944.         case ETB_COMMENT:
  945.             s1=file->comment;
  946.             if(s1==NULL)
  947.             {
  948.                 *buffer++=0;
  949.                 break;
  950.             }
  951.             bsize=commsize;
  952.             /* Fall through */
  953.         case ETB_NAME:
  954.             if(i==ETB_NAME)
  955.             {
  956.             s1=file->name;
  957.             bsize=namesize;
  958.             }
  959.             s2=(STRPTR)buf;
  960.             if(bsize)
  961.             {
  962.                 /* Fixed sized field */
  963.             if(bsize/sizeof(ULONG)>siz)
  964.                 return ERROR_BUFFER_OVERFLOW;
  965.             siz-=bsize/sizeof(ULONG)-1;
  966.             do
  967.                 if(!(*s2++=*s1++))
  968.                     break;
  969.             while(--bsize);
  970.             s2[-1]=0;
  971.             }else
  972.                 /* Variable sized field */
  973.             for(;;)
  974.             {
  975.                     for(k=0;k<sizeof(ULONG);k++)
  976.                         if(!(*s2++=*s1++))
  977.                         {
  978.                             for(;k<sizeof(ULONG);k++)
  979.                                 *s2++=0;
  980.                             break;
  981.                         }
  982.                     if(!--siz)
  983.                         return ERROR_BUFFER_OVERFLOW;
  984.                 }
  985.             buf=(ULONG*)s2;
  986.             break;
  987.         case ETB_TYPE:
  988.             *buf++=file->type;
  989.             break;
  990.         case ETB_PROTECT:
  991.             *buf++=file->protect;
  992.             break;
  993.         case ETB_SIZE:
  994.             *buf++=file->size;
  995.             break;
  996.         case ETB_DOSLIST:
  997.         case ETB_SIZEH:
  998.         case ETB_BLOCKSUSED:
  999.         case ETB_BLOCKSUSEDH:
  1000.         case ETB_DAYS:
  1001.         case ETB_MINUTES:
  1002.         case ETB_TICKS:
  1003.         case ETB_OWNERIDS:
  1004.         case ETB_DISKSTATE:
  1005.         case ETB_BYTESPERBLK:
  1006.         case ETB_DISKTYPE:
  1007.             *buf++=0;
  1008.             break;
  1009.         }
  1010.         siz--;
  1011.     }
  1012.     type<<=1;
  1013.     }
  1014.     *buffer=buf;
  1015.     *size=siz*sizeof(ULONG);
  1016.     return 0;
  1017. }
  1018.  
  1019. static LONG examine(struct filehandle *handle, ULONG *buffer, ULONG size, struct TagItem *tags)
  1020. {
  1021.     ULONG type[16], filesize=0, commsize=0;
  1022.     while(tags->ti_Tag!=TAG_END)
  1023.     {
  1024.         switch(tags->ti_Tag)
  1025.         {
  1026.             case EXA_TYPE:
  1027.                 type=tags->ti_Data;
  1028.                 break;
  1029.             case EXA_NAMESIZE:
  1030.                 filesize=tags->ti_Data;
  1031.                 break;
  1032.             case EXA_COMMENTSIZE:
  1033.                 commsize=tags->ti_Data;
  1034.                 break;
  1035.             default:
  1036.                 return ERROR_NOT_IMPLEMENTED;
  1037.         }
  1038.         tags++;
  1039.     }
  1040.     return examine_node((struct fnode *)handle->node, &buffer, &size, type, namesize, commsize);
  1041. }
  1042. #endif
  1043. static LONG delete_object(struct rambase *rambase, struct filehandle *filehandle, char *name)
  1044. {
  1045.     struct fnode *file=(struct fnode *)filehandle->node;
  1046.     if((struct fnode *)file->volume==file)
  1047.         return ERROR_OBJECT_WRONG_TYPE;
  1048.     if(file->usecount)
  1049.     return ERROR_OBJECT_IN_USE;
  1050.     if(!(file->protect&FIBF_DELETE))
  1051.     return ERROR_DELETE_PROTECTED;
  1052.     if(file->type==ST_USERDIR&&((struct dnode *)file)->list.mlh_Head->mln_Succ!=NULL)
  1053.     return ERROR_DIRECTORY_NOT_EMPTY;
  1054.     delete(rambase,file);
  1055.     return 0;
  1056. }
  1057.  
  1058. LONG die(struct rambase *rambase, struct filehandle *handle)
  1059. {
  1060.     struct cnode *dev;
  1061.     struct vnode *vol;
  1062.     struct dnode *dir;
  1063.     struct fnode *file;
  1064.     
  1065.     dev=(struct cnode *)handle->node;
  1066.     free_lock(rambase,handle);
  1067.     if(dev->type!=ST_LINKDIR||dev->self!=dev)
  1068.     return ERROR_OBJECT_WRONG_TYPE;
  1069.     vol=dev->volume;
  1070.     if(vol->volcount)
  1071.     return ERROR_OBJECT_IN_USE;
  1072.  
  1073.     RemDosEntry(vol->doslist);
  1074.     FreeDosEntry(vol->doslist);
  1075.     RemDosEntry(dev->doslist);
  1076.     FreeDosEntry(dev->doslist);
  1077.  
  1078.     while(vol->list.mlh_Head->mln_Succ!=NULL)
  1079.     {
  1080.         dir=(struct dnode *)vol->list.mlh_Head;
  1081.         if(dir->type==ST_USERDIR)
  1082.             while((file=(struct fnode *)RemHead((struct List *)&dir->list))!=NULL)
  1083.         AddTail((struct List *)&vol->list,(struct Node *)dir);
  1084.         delete(rambase,(struct fnode *)dir);
  1085.     }
  1086.     Strfree(rambase,vol->name);
  1087.     FreeMem(vol,sizeof(struct vnode));
  1088.  
  1089.     Strfree(rambase,dev->name);
  1090.     FreeMem(dev,sizeof(struct cnode));
  1091.     rambase->unitcount--;
  1092.     return 0;
  1093. }
  1094.  
  1095. void deventry(struct rambase *rambase)
  1096. {
  1097.     struct IOFileSys *iofs;
  1098.     LONG error=0;
  1099.     /*
  1100.         Init device port. AllocSignal() cannot fail because this is a
  1101.     freshly created task with all signal bits still free. 
  1102.     */
  1103.     rambase->port->mp_SigBit=AllocSignal(-1);
  1104.     rambase->port->mp_Flags=PA_SIGNAL;
  1105.     
  1106.     /* Get and process the messages. */
  1107.     for(;;)
  1108.     {
  1109.         while((iofs=(struct IOFileSys *)GetMsg(rambase->port))!=NULL)
  1110.         {
  1111.             switch(iofs->IOFS.io_Command)
  1112.             {
  1113.         case FSA_STARTUP:
  1114.             /*
  1115.             mount a new dos device (a new filesystem)
  1116.             Unit *root;    root handle on return
  1117.             STRPTR name;   device name without colon
  1118.             struct TagItem *args; further arguments
  1119.             */
  1120.             AddTail((struct List *)&rambase->waitdoslist,&iofs->IOFS.io_Message.mn_Node);
  1121.             continue;
  1122.  
  1123.         case FSA_DIE:
  1124.             /*
  1125.             Free the lock then try to dismount dos device
  1126.             Unit *root;    handle to device's root directory
  1127.             */
  1128.             AddTail((struct List *)&rambase->waitdoslist,&iofs->IOFS.io_Message.mn_Node);
  1129.             continue;
  1130.  
  1131.         case FSA_LOCATE_OBJECT:
  1132.             /*
  1133.             get handle on a file or directory
  1134.             Unit *current; current directory / new handle on return
  1135.             STRPTR name;   file- or directoryname
  1136.             LONG mode;     locking mode
  1137.             LONG protect;  protection flags if a new file is created
  1138.             */
  1139.             error=locate_object(rambase,(struct filehandle **)&iofs->IOFS.io_Unit,
  1140.                           (STRPTR)iofs->io_Args[0], iofs->io_Args[1]);
  1141.             break;
  1142.  
  1143.         case FSA_READ:
  1144.             /*
  1145.             read a number of bytes from a file
  1146.             Unit *current; filehandle
  1147.             APTR buffer;   data
  1148.             LONG numbytes; number of bytes to read / 
  1149.                            number of bytes read on return,
  1150.                            0 if there are no more bytes in the file
  1151.             */
  1152.             error=read(rambase,(struct filehandle *)iofs->IOFS.io_Unit,
  1153.                      (APTR)iofs->io_Args[0], &iofs->io_Args[1]);
  1154.             break;
  1155.  
  1156.         case FSA_WRITE:
  1157.             /*
  1158.             write a number of bytes to a file
  1159.             Unit *current; filehandle
  1160.             APTR buffer;   data
  1161.             LONG numbytes; number of bytes to write /
  1162.                        number of bytes written on return
  1163.             */
  1164.             error=write(rambase,(struct filehandle *)iofs->IOFS.io_Unit,
  1165.                       (APTR)iofs->io_Args[0], &iofs->io_Args[1]);
  1166.             break;
  1167.             
  1168.         case FSA_SEEK:
  1169.             /*
  1170.             set / read position in file
  1171.             Unit *current; filehandle
  1172.             LONG posh;
  1173.             LONG posl;     relative position /
  1174.                            old position on return
  1175.             LONG mode;     one of OFFSET_BEGINNING, OFFSET_CURRENT,
  1176.                        OFFSET_END
  1177.             */
  1178.             error=seek(rambase,(struct filehandle *)iofs->IOFS.io_Unit,
  1179.                      &iofs->io_Args[0], &iofs->io_Args[1], iofs->io_Args[2]);
  1180.             break;
  1181.             
  1182.         case FSA_FREE_LOCK:
  1183.             /*
  1184.             get rid of a handle
  1185.             Unit *current; filehandle
  1186.             */
  1187.             error=free_lock(rambase,(struct filehandle *)iofs->IOFS.io_Unit);
  1188.             break;
  1189. #if 0
  1190.         case FSA_EXAMINE:
  1191.             /*
  1192.             Get information about the current object
  1193.             Unit *current; current object
  1194.             ULONG *buffer;  to be filled
  1195.             ULONG size;    size of the buffer
  1196.             ULONG type;    type of information to get
  1197.             */
  1198.             error=examine((struct filehandle *)iofs->IOFS.io_Unit,
  1199.                           (ULONG *)iofs->io_Args[0], iofs->io_Args[1],
  1200.                           iofs->io_Args[2]);
  1201.             break;
  1202. #endif
  1203. /*
  1204.   FSA_DELETE_OBJECT - delete file or directory
  1205.     Unit *current; current directory
  1206.     STRPTR name;   filename
  1207.  
  1208.   FSA_MAKE_LINK
  1209.     Unit *current; current directory, untouched by the handler
  1210.     STRPTR name;   filename
  1211.     LONG target;   target handle for hardlinks/target name for softlinks
  1212.     LONG mode;     !=0 softlink
  1213.  
  1214.   FSA_CREATE_DIR
  1215.   FSA_RENAME
  1216.   FSA_SET_PROTECT
  1217.   FSA_SET_OWNER
  1218.   FSA_SET_DATE
  1219.   FSA_READ_LINK
  1220.   FSA_DISK_INFO
  1221.   FSA_SERIALIZE_DISK
  1222.   FSA_MORE_CACHE
  1223.   FSA_WAIT_CHAR
  1224.   FSA_INFO
  1225.   FSA_FLUSH
  1226.   FSA_SET_COMMENT
  1227.   FSA_TIMER
  1228.   FSA_INHIBIT
  1229.   FSA_DISK_TYPE
  1230.   FSA_DISK_CHANGE
  1231.   FSA_SCREEN_MODE
  1232.   FSA_READ_RETURN
  1233.   FSA_WRITE_RETURN
  1234.  
  1235.   FSA_SET_FILE_SIZE
  1236.     LONG current;
  1237.     LONG pos;
  1238.     LONG mode;
  1239.  
  1240.   FSA_WRITE_PROTECT
  1241.   FSA_SAME_LOCK
  1242.   FSA_CHANGE_SIGNAL
  1243.   FSA_FORMAT
  1244.   FSA_IS_FILESYSTEM
  1245.   FSA_CHANGE_MODE
  1246.   FSA_EXAMINE_ALL
  1247.   FSA_EXAMINE_FH
  1248.   FSA_ADD_NOTIFY
  1249.   FSA_REMOVE_NOTIFY
  1250.   FSA_EXAMINE_ALL_END
  1251.  
  1252. */
  1253.             }
  1254.             iofs->io_DosError=error;
  1255.             ReplyMsg(&iofs->IOFS.io_Message);
  1256.         }
  1257.         if(rambase->waitdoslist.mlh_Head->mln_Succ!=NULL)
  1258.         {
  1259.         if(!AttemptLockDosList(LDF_DEVICES|LDF_VOLUMES|LDF_WRITE))
  1260.             Delay(TICKS_PER_SECOND/2);
  1261.         else
  1262.         {
  1263.         while((iofs=(struct IOFileSys *)RemHead((struct List *)&rambase->waitdoslist))!=NULL)
  1264.         {
  1265.             if(iofs->IOFS.io_Command==FSA_STARTUP)
  1266.             error=startup(rambase,(STRPTR)iofs->io_Args[0],
  1267.                       (struct TagItem *)iofs->io_Args[1]);
  1268.             else
  1269.             error=die(rambase,(struct filehandle *)iofs->IOFS.io_Unit);
  1270.             iofs->io_DosError=error;
  1271.             ReplyMsg(&iofs->IOFS.io_Message);
  1272.         }
  1273.         UnLockDosList(LDF_DEVICES|LDF_VOLUMES|LDF_WRITE);
  1274.         }
  1275.     }
  1276. #if 0    
  1277.     if(rambase->iofs!=NULL)
  1278.     {
  1279.             iofs=rambase->iofs;
  1280.             if(iofs->IOFS.io_Message.mn_Node.ln_Type==NT_MESSAGE)
  1281.             {
  1282.             abort_notify(rambase,iofs);
  1283.         iofs->io_DosError=ERROR_BREAK;
  1284.         rambase->iofs=NULL;
  1285.         ReplyMsg(&iofs->IOFS.io_Message);
  1286.             }else
  1287.             {
  1288.         rambase->iofs=NULL;
  1289.         Signal(1,0);
  1290.             }
  1291.         }
  1292. #endif
  1293.         Wait(1<<rambase->port->mp_SigBit);
  1294.     }
  1295. }
  1296.  
  1297. const char end=0;
  1298.